package com.plian.system.service.sys.file;

import com.plian.Tools.*;
import com.plian.Tools.file.FilesUtil;
import com.plian.Tools.office.PDFUtil;
import com.plian.Tools.pagedata.PageData;
import com.plian.system.common.status.CustomCode;
import com.plian.system.config.RedisUtils;
import com.plian.system.config.exception.MyRuntimeException;
import com.plian.system.dao.sys.file.FileDao;
import com.plian.system.model.CommonCode;
import com.plian.system.model.ListResult;
import com.plian.system.model.ObjResult;
import com.plian.system.model.page.Page;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.lang3.StringUtils;
//import org.jodconverter.DocumentConverter;
//import org.jodconverter.office.OfficeException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 附件处理
 */
@Service
@Slf4j
public class FileService {

    private static final Logger LOGGER = LoggerFactory.getLogger(FileService.class);

    @Autowired
    FileDao fileDao;
//    @Autowired
//    private DocumentConverter documentConverter;
    @Autowired
    private Environment environment;
    @Autowired
    private RedisUtils redisUtils;

    private static final List<String> fileTypeList = Stream.of(".pdf",
            ".rar",
            ".jpg",
            ".zip",
            ".png",
            ".doc",
            ".pdf",
            ".bmp",
            ".ceb",
            ".jpg",
            ".tif",
            ".docx",
            ".rar",
            ".txt",
            ".zip",
            ".doc",
            ".xlsx",
            ".7z",
            ".wps",
            ".txt",
            ".tif",
            ".xls",
            ".gif",
            ".rtf",
            ".mp3",
            ".png",
            ".ppt",
            ".jpeg").collect(Collectors.toList());

    //附件上传
    public ObjResult upFiles(MultipartHttpServletRequest request) {
        try {
            List<PageData> list = FilesUtil.UpFiles(request);
            ObjResult objResult = new ObjResult(CommonCode.SUCCESS);

            //附件容器
            List<PageData> list_doc = new ArrayList<>();
            for (PageData pd : list) {
                list_doc.add(fileToFileInfo(pd));
            }

            PageData pd = new PageData();
            pd.put("list_doc", list_doc);
            objResult.setPageData(pd);
            return objResult;
        } catch (FileNotFoundException e) {
            log.error(ExceptionUtils.getFullStackTrace(e));
            throw new MyRuntimeException(new ObjResult(CommonCode.ERROR));
        } catch (MyRuntimeException e) {
            return new ObjResult(CustomCode.builder().message(e.getErrorInfo()).code(1999).success(false).build());
        }

    }

    public PageData fileToFileInfo(PageData pd) {
        String separator = File.separator;
        //附件
        PageData p1 = new PageData();
        String name = pd.getString("name");
        LOGGER.error("FileService:" + name);
        String path = pd.getString("url");
        p1.put("fileName", name);
        p1.put("filePath", path);
        p1.put("fileSize", pd.getString("size"));
        String id = UuidUtil.get32UUID();
        p1.put("id", id);
        //文件前缀
        String caselsh = name.substring(0, name.lastIndexOf("."));
        //文件后缀
        String fileTyle = name.substring(name.lastIndexOf("."));
        if (!fileTypeList.contains(fileTyle.toLowerCase())) {
            throw new MyRuntimeException("该文件类型不支持上传");
        }
        redisUtils.set(id, path);
        redisUtils.set(id + "_viewFileName", name);
        p1.put("viewFileName", name);
        if (!fileTyle.equalsIgnoreCase(".pdf")) {
            BigDecimal bigDecimal = new BigDecimal(pd.getString("size"));
            BigDecimal b = bigDecimal.divide(new BigDecimal("1048576"), 2, BigDecimal.ROUND_HALF_UP);
            if (b.floatValue() <= 10) {
                if (fileTyle.equalsIgnoreCase(".doc") ||
                        fileTyle.equalsIgnoreCase(".docx") ||
                        fileTyle.equalsIgnoreCase(".xls") ||
                        fileTyle.equalsIgnoreCase(".xlsx") ||
                        fileTyle.equalsIgnoreCase(".ppt") ||
                        fileTyle.equalsIgnoreCase(".pptx")
                ) {
//                    try {
//                        documentConverter.convert(new File(path + separator + name))
//                                .to(new File(path + separator + caselsh + ".pdf")).execute();
//                    } catch (OfficeException e) {
//                        log.error(ExceptionUtils.getFullStackTrace(e));
//                        throw new MyRuntimeException(new ObjResult(CommonCode.ERROR));
//                    }
                    p1.put("viewFileName", caselsh + ".pdf");
                }
                p1.put("isPrint", true);
            } else {
                p1.put("isPrint", false);
            }
        } else {
            p1.put("isPrint", true);
            p1.put("viewFileName", name);
        }
        p1.put("ext", fileTyle);
        return p1;
    }

    //批量保存
    public ObjResult saveAll(String parentId, List<HashMap> list_doc) {
//        try {
//            if (l != null && l.size() > 0) {
//                l.forEach(pageData -> {
//                    if (!pageData.containsKey("id") || StringUtil.isBlank((String) pageData.get("id"))) {
//                        pageData.put("id", UuidUtil.get32UUID());
//                    }
//                    pageData.put("parentId", parentid);
//                    pageData.put("fileName", pageData.get("itFileName").toString());
//                });
//                fileDao.saveAll(l);
//            }
//            ObjResult objResult = new ObjResult(CommonCode.SUCCESS);
//            return objResult;
//        } catch (Exception e) {
//            log.error(ExceptionUtils.getFullStackTrace(e));
//            throw new MyRuntimeException(new ObjResult(CommonCode.ERROR));
//        }
        //前端传来的附件

        //已存在的附件
        List<HashMap> same_doc = new ArrayList<>();
        List<PageData> same_doc1 = new ArrayList<>();
        //数据库存在的附件
        try {
            if (list_doc != null && list_doc.size() > 0) {
                List<PageData> list = fileDao.findParentId(parentId);
                if (list != null && list.size() > 0) {
                    list.forEach(pageData -> {
                        list_doc.forEach(pageData1 -> {
                            pageData1.put("parentId", parentId);
                            pageData1.put("fileName", pageData1.get("itFileName").toString());
                            if (Tools.notEmpty(pageData1.get("id").toString())) {
                                if (pageData.getString("id").equals(pageData1.get("id").toString())) {
                                    same_doc.add(pageData1);
                                    same_doc1.add(pageData);
                                }
                            }
                        });
                    });
                    //数据库存在，传来的不存在
                    list.removeAll(same_doc1);
                    if (list != null && list.size() > 0) {
                        List<String> l = new ArrayList<>();
                        list.forEach(pageData -> {
                            l.add(pageData.getString("id"));
                        });
                        //删除库
                        fileDao.del_ids(l);
                    }
                }

                //传来的存在，数据库不存在
                list_doc.removeAll(same_doc);
                if (list_doc != null && list_doc.size() > 0) {
                    list_doc.forEach(pageData -> {
                        pageData.put("parentId", parentId);
                        pageData.put("fileName", pageData.get("itFileName").toString());
                    });
                    fileDao.saveAll(list_doc);
                }
                ObjResult objResult = new ObjResult(CommonCode.SUCCESS);
                return objResult;
            } else {
                fileDao.del_ParentId(parentId);
                ObjResult objResult = new ObjResult(CommonCode.SUCCESS);
                return objResult;
            }
        } catch (Exception e) {
            log.error(ExceptionUtils.getFullStackTrace(e));
            throw new MyRuntimeException(new ObjResult(CommonCode.ERROR));
        }
    }

    //修改
    @Transactional(rollbackFor = RuntimeException.class)
    public ObjResult edit(String parentId, List<HashMap> list_doc) {
        //前端传来的附件

        //已存在的附件
        List<HashMap> same_doc = new ArrayList<>();
        List<PageData> same_doc1 = new ArrayList<>();
        //数据库存在的附件
        try {
            if (list_doc != null && list_doc.size() > 0) {
                List<PageData> list = fileDao.findParentId(parentId);
                if (list != null && list.size() > 0) {
                    list.forEach(pageData -> {
                        list_doc.forEach(pageData1 -> {
                            pageData1.put("parentId", parentId);
                            pageData1.put("fileName", pageData1.get("itFileName").toString());
                            if (Tools.notEmpty(pageData1.get("id").toString())) {
                                if (pageData.getString("id").equals(pageData1.get("id").toString())) {
                                    same_doc.add(pageData1);
                                    same_doc1.add(pageData);
                                }
                            }
                        });
                    });
                    //数据库存在，传来的不存在
                    list.removeAll(same_doc1);
                    if (list != null && list.size() > 0) {
                        List<String> l = new ArrayList<>();
                        list.forEach(pageData -> {
                            l.add(pageData.getString("id"));
                        });
                        //删除库
                        fileDao.del_ids(l);
                    }
                }

                //传来的存在，数据库不存在
                list_doc.removeAll(same_doc);
                if (list_doc != null && list_doc.size() > 0) {
                    list_doc.forEach(pageData -> {
                        pageData.put("parentId", parentId);
                        pageData.put("fileName", pageData.get("itFileName").toString());
                    });
                    fileDao.saveAll(list_doc);
                }
                ObjResult objResult = new ObjResult(CommonCode.SUCCESS);
                return objResult;
            } else {
                fileDao.del_ParentId(parentId);
                ObjResult objResult = new ObjResult(CommonCode.SUCCESS);
                return objResult;
            }
        } catch (Exception e) {
            log.error(ExceptionUtils.getFullStackTrace(e));
            throw new MyRuntimeException(new ObjResult(CommonCode.ERROR));
        }
    }

    //附件下载
    public void fileDown(PageData doc, HttpServletResponse response) throws Exception {
        String id = doc.getString("id");
        if (StringUtil.isBlank(id)) {
            throw new MyRuntimeException(new ObjResult("id为空，下载失败！"));
        }
        String name;
        String url;
        if (redisUtils.hasKey(id)) {
            url = (String) redisUtils.get(id);
            name = (String) redisUtils.get(id + "_viewFileName");
        } else {
            doc = fileDao.findbyId(id);
            name = doc.getString("fileName");
            url = doc.getString("filePath");
        }
        FilesUtil.DownFile(name, url, response);
    }

    //分页查询
    public ListResult<PageData> listPage(PageData pd) {
        Page page = new Page(true, pd);
        try {
            List<PageData> l = fileDao.listPage(page);
            l.forEach(pageData -> {
                pageData.put("viewFileName", pageData.getString("fileName"));
            });
            ListResult listResult = new ListResult(CommonCode.SUCCESS);
            listResult.setList(l);
            listResult.setTotal(page.getTotal());
            return listResult;
        } catch (Exception e) {
            log.error(ExceptionUtils.getFullStackTrace(e));
            throw new MyRuntimeException(new ObjResult(CommonCode.ERROR));
        }
    }

    public ObjResult listParentId(PageData pd) {
        String parentId = pd.getString("parentId");
        try {
            List<PageData> list_doc = fileDao.findParentId(parentId);
            list_doc.forEach(pageData -> {
                pageData.put("itFileName", pageData.getString("fileName"));
                pageData.put("viewFileName", pageData.getString("fileName"));
                String fileName = pageData.getString("fileName");
                //文件后缀
                String fileTyle = fileName.substring(fileName.lastIndexOf("."));
                if (!fileTyle.equalsIgnoreCase("pdf")) {
                    BigDecimal bigDecimal = new BigDecimal(pageData.getString("fileSize"));
                    BigDecimal b = bigDecimal.divide(new BigDecimal("1048576"), 2, BigDecimal.ROUND_HALF_UP);
                    if (b.floatValue() <= 20) {
                        pageData.put("isPrint", true);
                    } else {
                        pageData.put("isPrint", false);
                    }
                } else {
                    pageData.put("isPrint", true);
                }

                if (Tools.notEmpty(fileName)) {
                    String currFileName = fileName.substring(19);
                    if (StringUtil.isNotBlank(currFileName)) {
                        fileName = currFileName;
                    }
                    pageData.put("fileName", fileName);
                }
            });
            ObjResult objResult = new ObjResult(CommonCode.SUCCESS);
            PageData p = new PageData();
            p.put("list_doc", list_doc);
            objResult.setPageData(p);
            return objResult;
        } catch (Exception e) {
            log.error(ExceptionUtils.getFullStackTrace(e));
            throw new MyRuntimeException(new ObjResult(CommonCode.ERROR));
        }
    }

    //    附件转换
    public ObjResult topdf(PageData doc) {
        try {
            if (doc.containsKey("id")) {
                doc = fileDao.findbyId(doc.getString("id"));
            }

            String path = doc.getString("filePath");
            String name = doc.getString("fileName");
            File file = new File(path, name);
            //得到真实文件名
            String time = name.substring(0, 19);
            String n1 = name.substring(19);
            //文件前缀
            String caselsh = n1.substring(0, name.lastIndexOf("."));
            //文件后缀
//            String fileTyle=n1.substring(name.lastIndexOf("."));

            //pdf名称
            String pdfname = time + caselsh + ".pdf";
            String separator = File.separator;
            //文件转化
            if (file.exists()) {
//                documentConverter.convert(file).to(new File(path + separator + pdfname)).execute();
            }
            ObjResult objResult = new ObjResult(CommonCode.SUCCESS);
            PageData p = new PageData();
            p.put("filePath", path);
            p.put("fileName", pdfname);
            objResult.setPageData(p);
            return objResult;
        } catch (Exception e) {
            log.error(ExceptionUtils.getFullStackTrace(e));
            throw new MyRuntimeException(new ObjResult(CommonCode.ERROR));
        }

    }

    /**
     * 附件预览
     */
    public void view(PageData doc, HttpServletResponse res) throws Exception {
        if (doc.containsKey("id")) {
            doc = fileDao.findbyId(doc.getString("id"));
        }
        String path = doc.getString("filePath");
        String name = doc.getString("fileName");
        //文件前缀
        String caselsh = name.substring(0, name.lastIndexOf("."));
        //文件后缀
        String fileTyle = name.substring(name.lastIndexOf("."));
        String separator = File.separator;
        if (!fileTyle.equalsIgnoreCase(".pdf")) {
            File file = new File(path + separator + caselsh + ".pdf");
            if (!file.exists()) {
                if (fileTyle.equalsIgnoreCase(".doc") ||
                        fileTyle.equalsIgnoreCase(".docx") ||
                        fileTyle.equalsIgnoreCase(".xls") ||
                        fileTyle.equalsIgnoreCase(".xlsx") ||
                        fileTyle.equalsIgnoreCase(".ppt") ||
                        fileTyle.equalsIgnoreCase(".pptx")
                ) {
                    //如果不存在pdf则转义
//                    documentConverter.convert(new File(path + separator + name)).to(new File(path + separator + caselsh + ".pdf")).execute();
                    name = caselsh + ".pdf";
                    new PDFUtil(res, name, path);
                } else {
                    new PDFUtil(res, name, path);
                }
            } else {
                new PDFUtil(res, caselsh + ".pdf", path);
            }
        } else {
            new PDFUtil(res, name, path);
        }
    }

    public ResponseEntity<byte[]> excelDownload(String key) {
        if (!redisUtils.hasKey(key)) {
            throw new MyRuntimeException(new ObjResult("文件不存在，下载失败！"));
        }
        String excelName = (String) redisUtils.get(key);
        String excelPath = environment.getProperty("excel.path") + "/" + key + ".xlsx";
        ResponseEntity<byte[]> responseEntity = FileTools.exportExcel(excelPath, excelName);
        redisUtils.del(key);
        return responseEntity;
    }

    public void fileList(PageData pd) throws Exception {
        List<PageData> l = fileDao.findParentId(pd.getString("id"));
        for (int i = 1; i <= 9; i++) {
            List<PageData> l2 = new ArrayList<>();
            for (PageData pageData : l) {
                if (pageData.getString("type").equals("f" + i)) {
                    pageData.put("itFileName", pageData.getString("fileName"));
                    pageData.put("viewFileName", pageData.getString("fileName"));
                    String fileName = pageData.getString("fileName");
                    //文件后缀
                    String fileTyle = fileName.substring(fileName.lastIndexOf("."));
                    if (!fileTyle.equalsIgnoreCase("pdf")) {
                        BigDecimal bigDecimal = new BigDecimal(pageData.getString("fileSize"));
                        BigDecimal b = bigDecimal.divide(new BigDecimal("1048576"), 2, BigDecimal.ROUND_HALF_UP);
                        if (b.floatValue() <= 20) {
                            pageData.put("isPrint", true);
                        } else {
                            pageData.put("isPrint", false);
                        }
                    } else {
                        pageData.put("isPrint", true);
                    }

                    if (Tools.notEmpty(fileName)) {
                        fileName = fileName.substring(19);
                        pageData.put("fileName", fileName);
                    }
                    l2.add(pageData);
//                    break;
                }
            }
            pd.put("f" + i, l2);
        }
    }

    public void setViewInfo(PageData pd) {
        pd.put("itFileName", pd.getString("fileName"));
        pd.put("viewFileName", pd.getString("fileName"));
        String fileName = pd.getString("fileName");
        //文件后缀
        String fileType = fileName.substring(fileName.lastIndexOf("."));
        if (!"pdf".equalsIgnoreCase(fileType)) {
            BigDecimal bigDecimal = new BigDecimal(pd.getString("fileSize"));
            BigDecimal b = bigDecimal.divide(new BigDecimal("1048576"), 2, BigDecimal.ROUND_HALF_UP);
            if (b.floatValue() <= 20) {
                pd.put("isPrint", true);
            } else {
                pd.put("isPrint", false);
            }
        } else {
            pd.put("isPrint", true);
        }

        if (Tools.notEmpty(fileName)) {
            fileName = fileName.substring(19);
            pd.put("fileName", fileName);
        }
    }

    @Transactional(rollbackFor = RuntimeException.class)
    public ObjResult editByType(String parentId, List<HashMap> list_doc, String type) {
        //前端传来的附件
        PageData pd = new PageData();
        pd.put("parentId", parentId);
        pd.put("type", type);
        //已存在的附件
        List<HashMap> same_doc = new ArrayList<>();
        List<PageData> same_doc1 = new ArrayList<>();
        //数据库存在的附件
        try {
            if (list_doc != null && list_doc.size() > 0) {
                List<PageData> list = fileDao.findByParentIdAndType(pd);
                if (list != null && list.size() > 0) {
                    list.forEach(pageData -> {
                        list_doc.forEach(pageData1 -> {
                            pageData1.put("parentId", parentId);
                            pageData1.put("fileName", pageData1.get("itFileName").toString());
                            if (Tools.notEmpty(pageData1.get("id").toString())) {
                                if (pageData.getString("id").equals(pageData1.get("id").toString())) {
                                    same_doc.add(pageData1);
                                    same_doc1.add(pageData);
                                }
                            }
                        });
                    });
                    //数据库存在，传来的不存在
                    list.removeAll(same_doc1);
                    if (list != null && list.size() > 0) {
                        List<String> l = new ArrayList<>();
                        list.forEach(pageData -> {
                            l.add(pageData.getString("id"));
                        });
                        //删除库
                        fileDao.del_ids(l);
                    }
                }

                //传来的存在，数据库不存在
                list_doc.removeAll(same_doc);
                if (list_doc != null && list_doc.size() > 0) {
                    list_doc.forEach(pageData -> {
                        pageData.put("parentId", parentId);
                        pageData.put("fileName", pageData.get("itFileName").toString());
                    });
                    fileDao.saveAll(list_doc);
                }
                ObjResult objResult = new ObjResult(CommonCode.SUCCESS);
                return objResult;
            } else {
                fileDao.delByParentIdAndType(pd);
                ObjResult objResult = new ObjResult(CommonCode.SUCCESS);
                return objResult;
            }
        } catch (Exception e) {
            log.error(ExceptionUtils.getFullStackTrace(e));
            throw new MyRuntimeException(new ObjResult(CommonCode.ERROR));
        }
    }

    @Transactional(rollbackFor = RuntimeException.class)
    public void upYthFile(String... params) {
        String attachIds = params[0];
        String formId = params[1];
        String fileType = "";
        if (params.length > 2){
            fileType = params[2];
        }
        try {
            if (StringUtil.isNotBlank(fileType)){
                PageData pd = new PageData();
                pd.put("parentId", formId);
                pd.put("type", fileType);
                fileDao.delByParentIdAndType(pd);
            }else {
                fileDao.del_ParentId(formId);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        if (StringUtil.isBlank(attachIds)) {
            return;
        }
        List<Long> attachIdList = Func.toLongList(StringUtils.join(attachIds, StringPool.COMMA));
        List<MultipartFile> multipartFileList = new ArrayList<>();
//        for (Long attachId : attachIdList) {
//            YthFileInfoBean fileInfoBean = ythService.getAttach(attachId);
//            Response serviceResponse = ythService.downloadAttach(attachId);
//            try {
//                Response.Body body = serviceResponse.body();
//                InputStream inputStream = body.asInputStream();
//                MultipartFile multipartFile = getMultipartFile(inputStream, fileInfoBean.getOriginalName());
//                multipartFileList.add(multipartFile);
//            } catch (IOException e) {
//                e.printStackTrace();
//            }
//        }
        if (CollectionUtil.isNotEmpty(multipartFileList)) {
            List<PageData> pageDataList = FilesUtil.upFiles(multipartFileList);
            pageDataList.forEach(pageData -> {
                pageData.put("parentId", formId);
            });
            List<HashMap> fileList = new ArrayList<>();
            HashMap<String, String> extMap = FilesUtil.extMap();
            for (PageData filePd : pageDataList) {
                PageData fileInfoMap = fileToFileInfo(filePd);
                fileInfoMap.put("parentId", formId);
                if (StringUtil.isNotBlank(fileType)){
                    fileInfoMap.put("type", fileType);
                }
                String ext = fileInfoMap.getString("ext");
                if (extMap.containsKey(ext)) {
                    fileInfoMap.put("mime", extMap.get(ext));
                }
                fileList.add(fileInfoMap);
            }

            try {
                fileDao.saveAll(fileList);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
    }

    /**
     * 获取封装得MultipartFile
     *
     * @param inputStream inputStream
     * @param fileName    fileName
     * @return MultipartFile
     */
    public MultipartFile getMultipartFile(InputStream inputStream, String fileName) {
        FileItem fileItem = createFileItem(inputStream, fileName);
        return new CommonsMultipartFile(fileItem);
    }


    /**
     * FileItem类对象创建
     *
     * @param inputStream inputStream
     * @param fileName    fileName
     * @return FileItem
     */
    public FileItem createFileItem(InputStream inputStream, String fileName) {
        FileItemFactory factory = new DiskFileItemFactory(16, null);
        String textFieldName = "file";
        FileItem item = factory.createItem(textFieldName, MediaType.MULTIPART_FORM_DATA_VALUE, true, fileName);
        try {
            OutputStream os = item.getOutputStream();
            IOUtils.copy(inputStream, os);
            inputStream.close();
            os.close();
        } catch (IOException e) {
            log.error("文件流转换异常", e);
            throw new RuntimeException(e);
        }
        return item;
    }

}
